home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
telecomm
/
sticpsrc.lzh
/
SOURCE.ARC
/
SCC.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-08-15
|
53KB
|
1,797 lines
/*
* Generic driver for Z8530 SCC chip in SLIP, KISS or AX.25 mode.
*
* Written by R.E. Janssen (PE1CHL) using material from earlier
* EAGLE and PC100 drivers in this package.
*
* The driver has initially been written for my own Atari SCC interface
* board, but it could eventually replace the other SCC drivers.
*
* Unfortunately, there is little consistency between the different interface
* boards, as to the use of a clock source, the solution for the fullduplex
* clocking problem, and most important of all: the generation of the INTACK
* signal. Most designs do not even support the generation of an INTACK and
* the read of the interrupt vector provided by the chip.
* This results in lots of configuration parameters, and a fuzzy
* polltable to be able to support multiple chips connected at one interrupt
* line...
*
* when the constant SCC_HWTIMER is defined during compilation of SCC.C,
* we'll install the timer directly on the timer hardware interrupt, not on the
* timer-tick user-exit (int 1c) because some programs take over that one
* without saving and calling the original handler installed there...
*
*/
#define SCC_HWTIMER /* timer tick on hardware interrupt */
#ifdef ATARI_ST
# ifdef MWC
# include <osbind.h>
# endif
# ifdef __TURBOC__
# include <tos.h>
# endif
#endif
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include "global.h"
#include "mbuf.h"
#include "buffers.h"
#include "iface.h"
#include "slip.h"
#include "scc.h"
#include "8530.h"
#include "8536.h"
#include "ax25.h"
#include "trace.h"
/* variables used by the SCC interrupt handler in sccvec.s */
#ifdef ATARI_ST
ioaddr sccgpiploc; /* location of MFP GPIP register */
int sccgpipbit; /* bit# to test in MFP GPIP reg */
ioaddr sccisrloc; /* location of MFP ISR */
int sccisrbit; /* bit# to clear in MFP ISR */
extern void (*sccotvec)(); /* location to store old int vec */
struct sccinfo sccinfo; /* global info about SCCs */
struct sccchan *sccchan[2 * MAXSCC]; /* information per channel */
ioaddr sccvecloc; /* location to access for SCC vector */
unsigned char sccmaxvec; /* maximum legal vector from SCC */
ioaddr sccpolltab[MAXSCC+1][2]; /* polling table when no vectoring */
#endif
#ifdef MSDOS
static void (*orgivec)(); /* original interrupt vector */
extern void (*far sccotvec)(); /* location to store old int vec */
struct sccinfo sccinfo = {0}; /* global info about SCCs */
struct sccchan *sccchan[2 * MAXSCC] = {0}; /* information per channel */
ioaddr sccvecloc = {0}; /* location to access for SCC vector */
unsigned char sccmaxvec = {0}; /* maximum legal vector from SCC */
ioaddr sccpolltab[MAXSCC+1][2] = {0}; /* polling table when no vectoring */
# if ((defined(MSC) && defined(INLINE)) || (defined(__TURBOC__) && defined(inportb)))
static unsigned scc_delay (v) /* delay for about 5 PCLK cycles */
unsigned v; /* pass-through used for input */
{
return v; /* return the passed parameter */
}
# endif
#endif
unsigned char random = 0; /* random number for p-persist */
extern char nospace[];
static int scc_stop(),scc_raw(),scc_slipraw(),doscc();
static void scc_async(),scc_sdlc(),scc_recv();
static void scc_tossb(),scc_txon(),scc_txoff();
static int scc_ax25(),scc_aioctl(),scc_sioctl();
static unsigned int scc_speed();
/* Attach an SCC channel to the system, or initialize SCC driver.
* operation depends on argv[2]:
* when "init", the SCC driver is initialized, and global information about
* the hardware is set up.
* argv[0]: hardware type, must be "scc"
* argv[1]: number of SCC chips we will support
* argv[2]: mode, must be: "init" in this case
* argv[3]: base address of SCC chip #0 (hex)
* argv[4]: spacing between SCC chip base addresses
* argv[5]: offset from chip base address to channel A control register
* argv[6]: offset from chip base address to channel B control register
* argv[7]: offset from each channel's control register to data register
* argv[8]: address of INTACK/Read Vector port. 0 to read from RR3A/RR2B
* argv[9]: CPU interrupt vector number for all connected SCCs
* argv[10]: clock frequency (PCLK/RTxC) of all SCCs in cycles per second
* prefix with "p" for PCLK, "r" for RTxC clock (for baudrate gen)
* argv[11]: optional hardware type (for special features)
* argv[12]: optional extra parameter for special hardware
*
* otherwise, a single channel is attached using the specified parameters:
* argv[0]: hardware type, must be "scc"
* argv[1]: SCC channel number to attach, 0/1 for first chip A/B, 2/3 for 2nd...
* argv[2]: mode, can be:
* "slip", "kiss", "ax25"
* argv[3]: interface label, e.g., "sl0"
* argv[4]: maximum transmission unit, bytes
* argv[5]: interface speed, e.g, "1200". prefix with "d" when an external
* divider is available to generate the TX clock. When the clock
* source is PCLK, this can be a /32 divider between TRxC and RTxC.
* When the clock is at RTxC, the TX rate must be supplied at TRxC.
* This is needed only for AX.25 fullduplex.
* When this arg is given as "ext", the transmit and receive clock
* are external, and the BRG and DPLL are not used.
* argv[6]: callsign used on the radio channels
*/
int
scc_attach(argc,argv)
int argc;
char *argv[];
{
register struct interface *ifp;
struct sccchan *scc;
unsigned int chan,brgrate;
int pclk = 0;
char *p;
char r11;
int hwtype = 0,hwparam = 0;
#ifdef ATARI_ST
long save_ssp;
#endif
extern struct interface *ifaces;
int slip_send(),kiss_ioctl(),kiss_raw();
void kiss_recv(),slip_recv();
long atol(),htol();
/* first handle the special "init" mode, to initialize global stuff */
if(!strcmp(argv[2],"init")){
if(argc < 11) /* need at least argv[1]..argv[10] */
return -1;
if (isupper(argv[10][0]))
argv[10][0] = tolower(argv[10][0]);
if (argv[10][0] == 'p'){ /* wants to use PCLK as clock? */
pclk = 1;
argv[10]++;
} else {
if (argv[10][0] == 'r') /* wants to use RTxC? */
argv[10]++; /* that's the default */
}
if (argc > 11) /* optional hardware type */
hwtype = htoi(argv[11]); /* it is given in hex */
if (argc > 12) /* optional hardware param */
hwparam = htoi(argv[12]); /* also in hex */
return scc_init(atoi(argv[1]),(ioaddr) htol(argv[3]),atoi(argv[4]),
atoi(argv[5]),atoi(argv[6]),atoi(argv[7]),
(ioaddr) htol(argv[8]),atoi(argv[9]),
atol(argv[10]),pclk,hwtype,hwparam);
}
/* not "init", so it must be a valid mode to attach a channel */
if (strcmp(argv[2],"ax25") && strcmp(argv[2],"kiss") &&
strcmp(argv[2],"slip")){
printf("Mode %s unknown for SCC\n",argv[2]);
return -1;
}
if (!sccinfo.init){
printf("First init SCC driver\n");
return -1;
}
if ((chan = atoi(argv[1])) > sccinfo.maxchan){
printf("SCC channel %d out of range\n",chan);
return -1;
}
if (sccchan[chan] != NULLCHAN){
printf("SCC channel %d already attached\n",chan);
return -1;
}
/* create interface structure and fill in details */
if ((ifp = (struct interface *) calloc(1,sizeof(struct interface))) == NULLIF){
printf(nospace);
return -1;
}
if ((ifp->name = malloc(strlen(argv[3]) + 1)) == NULLCHAR){
printf(nospace);
free(ifp);
return -1;
}
strcpy(ifp->name,argv[3]);
ifp->mtu = atoi(argv[4]);
ifp->dev = chan;
ifp->recv = doscc;
ifp->stop = scc_stop;
if ((scc = (struct sccchan *) calloc(1,sizeof(struct sccchan))) == NULLCHAN){
printf(nospace);
free(ifp->name);
free(ifp);
return -1;
}
scc->ctrl = sccinfo.iobase + (chan / 2) * sccinfo.space + sccinfo.off[chan % 2];
scc->data = scc->ctrl + sccinfo.doff;
scc->iface = ifp;
sccchan[chan] = scc; /* put addr in table for interrupts */
switch (argv[2][0]) /* mode already checked above */
{
case 'a': /* AX.25 */
/* default: RXclk DPLL, TXclk BRG. BRG reprogrammed